package com.ksd.pug.service.article;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ksd.orm.pug.mapper.ArticleMapper;
import com.ksd.pug.commons.enums.ResultStatusEnumA;
import com.ksd.pug.commons.ex.PugBussinessException;
import com.ksd.pug.commons.threadlocal.UserThrealLocal;
import com.ksd.pug.commons.utils.fn.asserts.Vsserts;
import com.ksd.pug.pojo.Article;
import com.ksd.pug.pojo.SysLoginUser;
import com.ksd.pug.pojo.SysRole;
import com.ksd.pug.service.user.ISysLoginUserService;
import com.ksd.pug.utils.redis.PugRedisOperator;
import com.ksd.pug.vo.comment.ArticleVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: hcl
 * @date: 2022/1/24 14:57
 * @Description:
 */
@Service
@Slf4j
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {

    @Autowired
    private PugRedisOperator redisOperator;

    @Autowired
    private IArticleUserCollectService articleUserCollectService;

    @Autowired
    private ISysLoginUserService sysLoginUserService;

    /**
     * 统计用户创作数
     * @return
     */
    @Override
    public List<Map<String, Object>> countUserCraetion(Long userId){
        return this.baseMapper.countUserCraetion(userId);
    }

   /**
     * 查询文章列表信息并分页
     *
     * @return
     */
    @Override
    public IPage<Article> findArticlePage(ArticleVo articleVo) {
        // 1: 设置分页
        Page<Article> page = new Page<>(articleVo.getPageNo(), articleVo.getPageSize());
        // 2: 设置条件
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 3：查询过滤一些字段，为啥要这样做呢？因为在开放中很多时候，我们一些表存在大字段列，而这些返回的过程非常非常查询性能。
        lambdaQueryWrapper.select(Article.class,column -> !column.getColumn().equals("content"));
        // 4: 把未删除的查询出来，那些删除的数据可以做一个回收站去回收即可
        lambdaQueryWrapper.eq(Article::getIsdelete, articleVo.getIsDelete());
        // 5:根据名字进行模糊匹配
        // 多列搜索
        lambdaQueryWrapper.and(Vsserts.isNotEmpty(articleVo.getKeyword()), wrapper -> wrapper
                .like(Article::getName, articleVo.getKeyword())
                .or()
                .like(Article::getCategoryName, articleVo.getKeyword())
        );

        // 条件拼接分类
        lambdaQueryWrapper.eq(Vsserts.isNotNull(articleVo.getCategoryId()),Article::getCategoryId,articleVo.getCategoryId());
        lambdaQueryWrapper.eq(Vsserts.isNotNull(articleVo.getStatus()),Article::getStatus,articleVo.getStatus());

        // 6: 设置排序 根据文章排降序，代表，最新的放在最前
        lambdaQueryWrapper.orderByDesc(Article::getIstop);
        lambdaQueryWrapper.orderByDesc(Article::getCreateTime);
        // 7：最后返回
        return this.page(page, lambdaQueryWrapper);
    }

    /**
     * 查询文章列表信息并分页
     *
     * @return
     */
    @Override
    public IPage<Article> findArticlePage2(ArticleVo articleVo) {
        // 1: 设置分页
        Page<Article> page = new Page<>(articleVo.getPageNo(), articleVo.getPageSize());
        // 2: 设置条件
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 3：查询过滤一些字段，为啥要这样做呢？因为在开放中很多时候，我们一些表存在大字段列，而这些返回的过程非常非常查询性能。
        lambdaQueryWrapper.select(Article.class,column -> !column.getColumn().equals("content"));
        // 4: 把未删除的查询出来，那些删除的数据可以做一个回收站去回收即可
        lambdaQueryWrapper.eq(Article::getIsdelete, articleVo.getIsDelete());
        // 5:根据名字进行模糊匹配
        // 多列搜索
        lambdaQueryWrapper.and(Vsserts.isNotEmpty(articleVo.getKeyword()), wrapper -> wrapper
                .like(Article::getName, articleVo.getKeyword())
                .or()
                .like(Article::getCategoryName, articleVo.getKeyword())
        );

        // 条件拼接分类
        lambdaQueryWrapper.eq(Vsserts.isNotNull(articleVo.getCategoryId()),Article::getCategoryId,articleVo.getCategoryId());
        lambdaQueryWrapper.eq(Vsserts.isNotNull(articleVo.getStatus()),Article::getStatus,articleVo.getStatus());

        // 6: 设置排序 根据文章排降序，代表，最新的放在最前
        lambdaQueryWrapper.orderByDesc(Article::getCreateTime);

        //获取用户角色 如果只有普通用户 就只查询自己的文章
        SysLoginUser user = UserThrealLocal.get();
        List<SysRole> roleList = sysLoginUserService.findSysRoleByUserId(user.getId());
        //如果只有普通用户则加入查询条件自查自己的文章
        if(Vsserts.isNotNull(roleList)){
            List<String> collect = roleList.stream().map(SysRole::getName).collect(Collectors.toList());
            if(collect.size()==1 && collect.get(0).equals("普通用户")){
                lambdaQueryWrapper.eq(Article::getUserId,user.getId());
            }
        }
        // 7：最后返回
        return this.page(page, lambdaQueryWrapper);
    }

    @Override
    public List<Article> findArticleMy(ArticleVo articleVo) {

        // 2: 设置条件
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 3：查询过滤一些字段，为啥要这样做呢？因为在开放中很多时候，我们一些表存在大字段列，而这些返回的过程非常非常查询性能。
        lambdaQueryWrapper.select(Article.class,column -> !column.getColumn().equals("content"));
        // 4: 把未删除的查询出来
        lambdaQueryWrapper.eq(Article::getIsdelete, 0);
        lambdaQueryWrapper.eq(Article::getStatus, 1);
        //查询自己的文章
        SysLoginUser user = UserThrealLocal.get();
        lambdaQueryWrapper.eq(Article::getUserId, user.getId());
        //根据时间排序
        lambdaQueryWrapper.orderByDesc(Article::getCreateTime);
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public IPage<Article> findArticleMyPage(ArticleVo articleVo) {
        // 1: 设置分页
        Page<Article> page = new Page<>(articleVo.getPageNo(), articleVo.getPageSize());
        // 2: 设置条件
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 3：查询过滤一些字段，为啥要这样做呢？因为在开放中很多时候，我们一些表存在大字段列，而这些返回的过程非常非常查询性能。
        lambdaQueryWrapper.select(Article.class,column -> !column.getColumn().equals("content"));
        // 4: 把未删除的查询出来，那些删除的数据可以做一个回收站去回收即可
        lambdaQueryWrapper.eq(Article::getIsdelete, articleVo.getIsDelete());
        // 5:根据名字进行模糊匹配
        // 多列搜索
        lambdaQueryWrapper.and(Vsserts.isNotEmpty(articleVo.getKeyword()), wrapper -> wrapper
                .like(Article::getName, articleVo.getKeyword())
                .or()
                .like(Article::getCategoryName, articleVo.getKeyword())
        );

        // 条件拼接分类
        lambdaQueryWrapper.eq(Vsserts.isNotNull(articleVo.getCategoryId()),Article::getCategoryId,articleVo.getCategoryId());
        lambdaQueryWrapper.eq(Vsserts.isNotNull(articleVo.getStatus()),Article::getStatus,articleVo.getStatus());

        //查询自己的文章
        SysLoginUser user = UserThrealLocal.get();
        lambdaQueryWrapper.eq(Article::getUserId, user.getId());

        // 6: 设置排序 根据文章排降序，代表，最新的放在最前
        lambdaQueryWrapper.orderByDesc(Article::getCreateTime);
        return this.page(page, lambdaQueryWrapper);
    }

    /**
     * 保存和修改文章
     *
     * @param article
     */
    @Override
    public Article saveUpdateArticle(Article article) {
        //保存的时候放入作者信息
        if(null == article.getId() || "".equals(article.getId())){
            SysLoginUser user = UserThrealLocal.get();
            article.setUserId(user.getId());
            article.setUserName(user.getNickname());
            article.setUserAvatar(user.getAvatar());
        }
        return this.saveOrUpdate(article) ? article : null;
    }


    /**
     * 根据文章id删除文章
     *
     * @param id
     * @return
     */
    @Override
    public boolean delArticle(Long id) {
        return this.removeById(id);
    }

    /**
     * 根据文章ids删除文章
     *
     * @param ids
     * @return
     */
    @Override
    public boolean delBatchArticle(String ids) {
        try {
            // 1 : 把数据分割
            String[] strings = ids.split(",");
            // 2: 组装成一个List<Article>
            List<Article> ArticleList = Arrays.stream(strings).map(idstr -> {
                Article Article = new Article();
                Article.setId(new Long(idstr));
                Article.setIsdelete(1);
                return Article;
            }).collect(Collectors.toList());
            // 3: 批量删除
            return this.updateBatchById(ArticleList);
        } catch (Exception ex) {
            throw new PugBussinessException(ResultStatusEnumA.IDS_ERROR_STATUS);
        }
    }


    /**
     * 根据文章id查询文章
     *
     * @param id
     * @return
     */
    @Override
    public Article getArticle(Long id) {
        Article byId = this.getById(id);
        Article article = new Article();
        Integer views = byId.getViews()+1;
        article.setViews(views);
        article.setId(byId.getId());
        // 把redis中文章的赞数返回
        String countStr = redisOperator.getHashValue("redis:user:zan:like",id+"");
        if(Vsserts.isNotEmpty(countStr)) {
            byId.setZannum(Integer.valueOf(countStr));
            article.setZannum(Integer.valueOf(countStr));
        }else{
            byId.setZannum(0);
            article.setZannum(0);
        }
        // 把redis中文章的收藏数返回
        String countStr2 = redisOperator.getHashValue("redis:user:collect:like",id+"");
        if(Vsserts.isNotEmpty(countStr2)) {
            byId.setCollections(Integer.valueOf(countStr2));
            //article.setCollections(Integer.valueOf(countStr2));
        }else{
            byId.setCollections(0);
            //article.setCollections(0);
        }
        //获取评论数
        String s = redisOperator.get("article:comment:count:" + article.getId());
        if(Vsserts.isNotEmpty(s)){
            byId.setPingluns(Integer.parseInt(s));
            article.setPingluns(Integer.parseInt(s));
        }
        this.updateById(article);
        SysLoginUser user = UserThrealLocal.get();
        log.info("获取到当前用户是{}",user);

        if(Vsserts.isNotNull(user)){
            // 获取某个用户是否点击该文章的赞
            String hget = redisOperator.hget("redis:zan:like:user", user.getId() + ":" + id);
            if (Vsserts.isNotEmpty(hget)) {
                byId.setIszan(1);
            } else {
                byId.setIszan(0);
            }
            // 获取某个用户是否点击该文章的收藏
            String hget2 = redisOperator.hget("redis:collect:like:user", user.getId() + ":" + id);
            if (Vsserts.isNotEmpty(hget2)) {
                byId.setIsshoucang(1);
            } else {
                byId.setIsshoucang(0);
            }

        }
        else{
            byId.setIszan(0);
            byId.setIsshoucang(0);
        }
        return byId;
    }

    /**
     * 查询热门文章
     *
     * @return
     */
    @Override
    public List<Article> findArticleTop(ArticleVo articleVo) {
        // 1: 设置分页
        Page<Article> page = new Page<>(articleVo.getPageNo(), articleVo.getPageSize());
        // 2: 设置条件
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 3：查询过滤一些字段，为啥要这样做呢？因为在开放中很多时候，我们一些表存在大字段列，而这些返回的过程非常非常查询性能。
        lambdaQueryWrapper.select(Article.class,column -> !column.getColumn().equals("content"));
        // 4: 把未删除的查询出来
        lambdaQueryWrapper.eq(Article::getIsdelete, 0);
        // 5: 把发布的查询出来
        lambdaQueryWrapper.eq(Article::getStatus,1);

        // 6: 设置排序 根据文章排降序，代表，最新的放在最前
        lambdaQueryWrapper.orderByDesc(Article::getViews);
        // 7：最后返回
        return this.page(page, lambdaQueryWrapper).getRecords();
    }

    /**
     * 文章点赞
     *
     * @return
     */
    @Override
    public int articleZanPlus(Long articleId) {
        SysLoginUser user = UserThrealLocal.get();
        //1: 评论表zannum + 1
        redisOperator.incrementHash("redis:user:zan:like",articleId+"",1L);
        redisOperator.setHashValue("redis:zan:like:user", user.getId() + ":" + articleId, "1");
        return 1;
    }

    /**
     * 文章取消点赞
     *
     * @return
     */
    @Override
    public int articleZanMius(Long articleId) {
        SysLoginUser user = UserThrealLocal.get();
        //1: 评论表zannum + 1
        redisOperator.decrementHash("redis:user:zan:like",articleId+"",1L);
        redisOperator.hdel("redis:zan:like:user", user.getId() + ":" + articleId);
        return 1;
    }

    /**
     * 文章收藏
     *
     * @return
     */
    @Override
    public int articleCollectPlus(Long articleId) {
        SysLoginUser user = UserThrealLocal.get();
        //1: 评论表zannum + 1
        redisOperator.incrementHash("redis:user:collect:like",articleId+"",1L);
        redisOperator.setHashValue("redis:collect:like:user", user.getId() + ":" + articleId, "1");
        articleUserCollectService.getCollect(articleId);
        return 1;
    }

    /**
     * 文章取消收藏
     *
     * @return
     */
    @Override
    public int articleCollectMius(Long articleId) {
        SysLoginUser user = UserThrealLocal.get();
        //1: 评论表zannum + 1
        redisOperator.decrementHash("redis:user:collect:like",articleId+"",1L);
        redisOperator.hdel("redis:collect:like:user", user.getId() + ":" + articleId);
        articleUserCollectService.removeCollect(articleId);
        return 1;
    }
}
